package com.xinchao.service.impl;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.google.common.collect.Lists;
import com.xinchao.common.bo.DeviceStateChangeBO;
import com.xinchao.core.cache.redis.RedisCacheDao;
import com.xinchao.core.constant.*;
import com.xinchao.core.exception.ServiceException;
import com.xinchao.core.util.DateUtils;
import com.xinchao.core.util.HttpUtils;
import com.xinchao.core.util.NumberUtils;
import com.xinchao.dao.DeviceMapper;
import com.xinchao.dao.DeviceSettingMapper;
import com.xinchao.model.Area;
import com.xinchao.model.DeviceSetting;
import com.xinchao.model.OperationLog;
import com.xinchao.model.User;
import com.xinchao.model.dto.DeviceInfoListDTO;
import com.xinchao.model.dto.UpdateDeviceDetailDTO;
import com.xinchao.model.page.PageInfo;
import com.xinchao.model.vo.*;
import com.xinchao.service.DeviceInfoService;
import com.xinchao.service.OperationLogService;
import com.xinchao.service.UserService;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;

@Service(value = "cpDeviceInfoService")
public class DeviceInfoServiceImpl implements DeviceInfoService {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());
    @Autowired
    DeviceMapper deviceMapper;
    @Autowired
    DeviceSettingMapper deviceSettingMapper;
    @Autowired
    private RedisCacheDao redisCacheDao;
    @Autowired
    private OperationLogService operationLogService;
    @Autowired
    private UserService userService;

    /**
     * 获取终端管理分页列表
     * hanqr 2018-08-07
     *
     * @param cityName      当前登录城市名称
     * @param machineNumber 机器码
     * @param propertyName  物业名称
     * @param deviceMac     设备mac
     * @param deviceIp      设备IP
     * @param administrator 管理人员
     * @param district      区/县编码
     * @param onlineStatus  在线状态（0.在线; 1.离线）
     * @param deviceStatus  设备状态:（0:可售  1:预拆除  2:维护）
     * @param pageNum       当前页码
     * @param pageSize      每页条数
     * @return
     */
    @Override
    public PageInfo<DeviceInfoListDTO> listByPage(String cityName, String machineNumber, String propertyName, String deviceMac,
                                                  String deviceIp, String administrator, String district, Integer onlineStatus, Integer deviceStatus,String softwareVersion,String firmwareVersion,
                                                  Integer pageNum, Integer pageSize) {
        PageHelper.startPage(pageNum, pageSize);
        Page<DeviceInfoListDTO> page = deviceMapper.listByPage(cityName, machineNumber, propertyName, deviceMac, deviceIp, administrator, district, onlineStatus, deviceStatus,softwareVersion,firmwareVersion);
        if (page == null) {
            return new PageInfo<>(pageNum, pageSize, 0, Lists.newArrayList());
        }
        List<DeviceInfoListDTO> result = page.getResult();
        List<DeviceInfoListDTO> newResult = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(result)) {
            String currentMonthTraffic = "";
            DeviceInfoListDTO deviceInfoListDTO = null;
            for (DeviceInfoListDTO aResult : result) {
                deviceInfoListDTO = aResult;
                currentMonthTraffic = deviceInfoListDTO.getCurrentMonthTraffic();
                if (StringUtils.isNotBlank(currentMonthTraffic)) {
                    if (currentMonthTraffic.endsWith(BusinessConstant.DATA_UNIT_M)) {
                        currentMonthTraffic = currentMonthTraffic.substring(0, (currentMonthTraffic.length() - 1));
                    }
                    //保留两位有效小数，第三位小数大于0时第二位小数+1
                    currentMonthTraffic = NumberUtils.parseDouble(currentMonthTraffic);
                    deviceInfoListDTO.setCurrentMonthTraffic(currentMonthTraffic + BusinessConstant.DATA_UNIT_M);
                }
                newResult.add(deviceInfoListDTO);
            }
        }
        PageInfo<DeviceInfoListDTO> pageInfo = new PageInfo<>();
        pageInfo.setPageNum(pageNum);
        pageInfo.setPageSize(pageSize);
        pageInfo.setTotal(page.getTotal());
        pageInfo.setList(newResult);
        return pageInfo;
    }

    /**
     * 远程关机指令
     * hanqr 2018-08-10
     *
     * @param deviceCodes 终端唯一编码
     * @param user        操作用户
     * @param ip          操作Ip
     * @throws ServiceException
     */
    @Override
    @Transactional(readOnly = false, rollbackFor = Exception.class)
    public void shutdown(String deviceCodes, User user, String ip) throws ServiceException {
        DeviceSetting setting = new DeviceSetting();
        setting.setShutDownOnce(Boolean.TRUE);
        deviceSettingAndSaveLog(DeviceSettingType.SHUT_DOWN, deviceCodes, user, ip, setting);
    }

    /**
     * 远程重启终端
     * hanqr 2018-08-10
     *
     * @param deviceCodes 终端唯一编码
     * @param user        当前登陆用户
     * @param ip          操作Ip
     * @throws ServiceException
     */
    @Override
    @Transactional(readOnly = false, rollbackFor = Exception.class)
    public void restart(String deviceCodes, User user, String ip) throws ServiceException {
        DeviceSetting setting = new DeviceSetting();
        setting.setRestartOnce(Boolean.TRUE);
        deviceSettingAndSaveLog(DeviceSettingType.RESTART, deviceCodes, user, ip, setting);
    }

    /**
     * 设置定时开关机
     * hanqr 2018-08-13
     *
     * @param deviceCodes 终端唯一编码
     * @param user        当前登陆用户
     * @param ip          操作Ip
     * @param bootTime    开机时间
     * @param offTime     关机时间
     * @throws ServiceException
     */
    @Override
    @Transactional(readOnly = false, rollbackFor = Exception.class)
    public void setBootAndOffTimmer(String deviceCodes, User user, String ip, String bootTime, String offTime) throws ServiceException {
        DeviceSetting setting = new DeviceSetting();
        setting.setTimeBoot(bootTime);
        setting.setTimeShutdown(offTime);
        deviceSettingAndSaveLog(DeviceSettingType.BOOT_OFF_TIMER, deviceCodes, user, ip, setting);
    }

    /**
     * 设置音量
     * hanqr 2018-08-13
     *
     * @param deviceCodes 终端唯一编码
     * @param user        当前登陆用户
     * @param ip          操作Ip
     * @param vol         音量
     * @throws ServiceException
     */
    @Override
    @Transactional(readOnly = false, rollbackFor = Exception.class)
    public void setVolume(String deviceCodes, User user, String ip, Integer vol) throws ServiceException {
        DeviceSetting setting = new DeviceSetting();
        setting.setDeviceVolume(vol);
        deviceSettingAndSaveLog(DeviceSettingType.SET_VOLUME, deviceCodes, user, ip, setting);
    }

    /**
     * 保存终端设置以及日志
     * hanqr 2018-08-10
     *
     * @param settingType 操作类型
     * @param deviceCodes 终端唯一编码
     * @param user        操作用户
     * @param ip          操作Ip
     * @param setting     终端设置对象
     */
    void deviceSettingAndSaveLog(DeviceSettingType settingType, String deviceCodes, User user, String ip, DeviceSetting setting) throws ServiceException {
        List<String> codeList = null;
        String splitChar = ",";
        codeList = Arrays.asList(deviceCodes.split(splitChar));
        if (CollectionUtils.isNotEmpty(codeList)) {
            StringBuilder msg = new StringBuilder("");
            for (String deviceCode : codeList) {
                // 根据deviceCode查询终端信息
                DeviceDetailVO deviceDetailVO = deviceMapper.getDeviceDetailByDeviceCode(deviceCode);
                if (deviceDetailVO != null) {
                    msg.append(",");
                    msg.append(deviceDetailVO.getMachineNumber());
                }
            }
            String operationMsg = String.format("操作行为：%s. 操作对象：[终端:%s]", settingType.getSettingType(), msg.substring(1));
            logger.info(operationMsg);
            // 记录批次号（时间戳）保证数据库跟缓存中更新时间一致
            Long serialNo = System.currentTimeMillis();
            // 1.设置信息同步到数据库
            setting.setUpdateTime(serialNo);
            updateDeviceSetting(setting, codeList);
            // 2.保存操作日志
            saveOperationLog(operationMsg, user, ip);
            // 3.将最新状态更新到缓存
            flushDeviceStateCache(settingType, codeList, serialNo);
        }
    }

    /**
     * 将终端最新状态或设置更新到缓存
     * hanqr 2018-08-10
     *
     * @param settingType 设置类型
     * @param codeList    终端唯一编码list
     * @param serialNo    批次号，唯一且有意义。（如：时间戳）
     */
    @Override
    public void flushDeviceStateCache(DeviceSettingType settingType, List<String> codeList, Long serialNo) {
        // 将更新存储到缓存的业务，不应受事务控制（即：及时缓存更新失败，或操作过程抛出异常也应当保证数据的正常入库操作）
        try {
            for (Iterator<String> it = codeList.iterator(); it.hasNext(); ) {
                String deviceCode = it.next();

                // 设备操作
                DeviceStateChangeBO deviceStateBO = (DeviceStateChangeBO) redisCacheDao.getCache(CacheConstant.CACHE_NAME_DEVICE_SETTING, deviceCode);
                if (deviceStateBO == null) {
                    deviceStateBO = new DeviceStateChangeBO();
                }
                switch (settingType) {
                    // 关机
                    case SHUT_DOWN:
                        // 重启
                    case RESTART:
                        // 定时开关机
                    case BOOT_OFF_TIMER:
                        // 设置音量
                    case SET_VOLUME:
                        // 测速
                    case TEST_NETWORK_SPEED:
                        deviceStateBO.setNewSetting(true);
                        deviceStateBO.setNewSettingUpdateTime(serialNo);
                        break;
                    // 软件升级
                    case SOFTWARE_UPGRADE:
                        // 固件升级
                    case FIRMWARE_UPGRADE:
                        deviceStateBO.setNewUpgrade(true);
                        deviceStateBO.setNewUpgradeUpdateTime(serialNo);
                        break;
                    default:
                        break;
                }
                redisCacheDao.putCache(CacheConstant.CACHE_NAME_DEVICE_SETTING, deviceCode, deviceStateBO);
            }
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("flushDeviceStateCache 刷新缓存业务异常：" + e.getMessage(), e);
        }

    }

    /**
     * 终端service保存操作日志
     *
     * @param operContent 操作内容
     * @param user        当前登录用户
     * @param ip          当前ip
     */
    private void saveOperationLog(String operContent, User user, String ip) {
        // 保存操作日志
        OperationLog operationLog = new OperationLog();
        operationLog.setOperationContent(operContent);
        operationLog.setOperationModule(ModuleConstant.MODULE_DEVICE_MNG);
        operationLog.setOperationStatus(BusinessConstant.OPERATION_LONG_OPERATION_STATUS_SUCCESS);
        operationLog.setOperationTime(System.currentTimeMillis());
        operationLog.setUserName(user.getUserName());
        operationLog.setRealname(user.getRealname());
        operationLog.setOperationIp(ip);
        operationLogService.saveOperationLog(operationLog);
    }

    /**
     * 终端设置信息同步到数据库
     *
     * @param setting  设置信息
     * @param codeList 终端唯一编码list
     * @return
     */
    @Override
    @Transactional(readOnly = false, rollbackFor = Exception.class)
    public void updateDeviceSetting(DeviceSetting setting, List<String> codeList) {
        deviceSettingMapper.updateDeviceSetting(setting, codeList);
    }

    /**
     * 根据城市编码查询所有行政区域
     * hanqr 2018-08-07
     *
     * @param cityCode 城市编码
     * @return
     */
    @Override
    public List<Area> getDistrictByCityCode(String cityCode) {
        return deviceMapper.getDistrictByCityCode(cityCode);
    }

    /**
     * 获取终端详情
     *
     * @param deviceId 终端ID
     * @return DeviceDetailVO
     * @author linqiang
     */
    @Override
    public DeviceDetailVO getDeviceDetail(Long deviceId) {
        return deviceMapper.getDeviceDetail(deviceId);
    }

    /**
     * 修改终端信息
     *
     * @param deviceDetail 修改的终端信息
     */
    @Override
    @Transactional(readOnly = false, rollbackFor = Exception.class)
    public void updateDevice(UpdateDeviceDetailDTO deviceDetail, HttpServletRequest request) {
        deviceMapper.updateDevice(deviceDetail);
        operationLogService.saveSuccessOperationLog("操作行为：修改终端信息. 操作对象：[终端:" + deviceDetail.getMachineNumber() + "]"
                , ModuleConstant.MODULE_DEVICE_MNG, request);
    }

    /**
     * 导出终端管理列表
     * hanqr 2018-08-08
     *
     * @param cityName      当前登录城市名称
     * @param machineNumber 机器码
     * @param propertyName  物业名称
     * @param deviceMac     设备mac
     * @param deviceIp      设备IP
     * @param administrator 管理人员
     * @param district      区/县
     * @param onlineStatus  在线状态（0.在线; 1.离线）
     * @param deviceStatus  设备状态:（0:可售  1:预拆除  2:维护）
     *
     *
     *
     * @return
     */
    @Override
    public List<DeviceInfoExportListVO> listExportDevice(String cityName, String machineNumber, String propertyName, String deviceMac, String deviceIp, String administrator, String district, Integer onlineStatus, Integer deviceStatus, String softwareVersion, String firmwareVersion) {
        Page<DeviceInfoExportListVO> page = deviceMapper.exportListByPage(cityName, machineNumber, propertyName, deviceMac, deviceIp, administrator, district, onlineStatus, deviceStatus,softwareVersion, firmwareVersion);
        if (page == null) {
            return Lists.newArrayList();
        }
        return page.getResult();
    }

    /**
     * 统计终端数
     *
     * @param currentCity 当前城市
     * @return DeviceCountVO
     * @author linqiang
     */
    @Override
    public DeviceCountVO countByCity(String currentCity) {
        return deviceMapper.countByCity(currentCity);
    }

    /**
     * 查询终端日志分页列表
     * hanqr 2018-08-09
     *
     * @param deviceCode 机器编码
     * @param startTime  开始时间
     * @param endTime    结束时间
     * @param logType    日志类型 crash:崩溃日志, run:运行日志, play:播放日志
     * @param pageNum    当前页
     * @param pageSize   每页条数
     * @return
     */
    @Override
    public Page<DeviceLogListVO> listDeviceLogs(String deviceCode, String startTime, String endTime, String logType, Integer pageNum, Integer pageSize) {
        //把格式化字符串时间转化为Long类型时间戳
        Long startTimeL = null;
        Long endTimeL = null;
        try {
            if (StringUtils.isNotBlank(startTime)) {
                startTimeL = DateUtils.stringTimeToLongTimeStamp(startTime, DateFormatConstant.LONG_DATE_FORMAT_STR);
            }
            if (StringUtils.isNotBlank(endTime)) {
                endTimeL = DateUtils.stringTimeToLongTimeStamp(endTime, DateFormatConstant.LONG_DATE_FORMAT_STR);
            }
        } catch (ParseException e) {
            e.printStackTrace();
        }
        PageHelper.startPage(pageNum, pageSize);
        return deviceMapper.listDeviceLogs(deviceCode, startTimeL, endTimeL, logType);
    }

    /**
     * 终端管理授权
     * hanqr 2018-08-09
     *
     * @param deviceCodes  终端编码(多个编码之间用逗号隔开)
     * @param administrans 授权人id(多个id之间用逗号隔开)
     * @param user         当前登录用户
     * @param request
     */
    @Override
    @Transactional(readOnly = false, rollbackFor = Exception.class)
    public void deviceAuthority(String deviceCodes, String administrans, User user, HttpServletRequest request) {
        StringBuilder machineNumbersb = new StringBuilder();
        StringBuilder administransb = new StringBuilder();
        String[] deviceCode = deviceCodes.split(",");
        for (int i = 0; i < deviceCode.length; i++) {
            deviceMapper.deviceAuthority(deviceCode[i], administrans);
            // 查询机器码
            DeviceDetailVO deviceDetailVO = deviceMapper.getDeviceDetailByDeviceCode(deviceCode[i]);
            if (deviceDetailVO != null) {
                machineNumbersb.append(deviceDetailVO.getMachineNumber() + ",");
            }
        }
        String[] adminnstran = administrans.split(",");
        for (int i = 0; i < adminnstran.length; i++) {
            // 查询授权人
            User userAd = userService.getUserById(Long.valueOf(adminnstran[i]));
            if (userAd != null) {
                administransb.append(userAd.getRealname() + ",");
            }
        }
        // 操作日志
        String machineNumberStr = null;
        String administranStr = null;
        if (machineNumbersb.length() > 0) {
            machineNumberStr = machineNumbersb.substring(0, machineNumbersb.length() - 1);
        }
        if (administransb.length() > 0) {
            administranStr = administransb.substring(0, administransb.length() - 1);
        }
        saveOperationLog("终端:" + machineNumberStr + "授权给管理人:" + administranStr, user, HttpUtils.getRemortIP(request));
    }

    /**
     * 查询所有终端中所有的固件版本号
     *
     * @return List<String>
     */
    @Override
    public List<String> listAllFirmwareVersion() {
        return deviceMapper.listAllFirmwareVersion();
    }

    /**
     * 终端升级分页筛选查询终端
     *
     * @param cityName     当前登录城市名称
     * @param softVer      软件版本
     * @param firmVer      固件版本
     * @param onlineStatus 在线状态(0:在线 1:离线)
     * @param upgradeType  更新类型(0:APK 1:固件)
     * @param deviceModel  机型
     * @param district     行政区
     * @param pageNum
     * @param pageSize
     * @return
     */
    @Override
    public PageInfo<UpgradeDeviceListVO> listUpgradeDeviceByPage(String cityName, String softVer, String firmVer, Integer onlineStatus, Integer upgradeType,
                                                                 String deviceModel, String district, Integer pageNum, Integer pageSize) {
        pageNum = pageNum == null ? PageConstant.DEFAULT_PAGE_NUM : pageNum;
        pageSize = pageSize == null ? PageConstant.DEFAULT_PAGE_SIZE : pageSize;
        PageHelper.startPage(pageNum, pageSize);
        Page<UpgradeDeviceListVO> page = deviceMapper.listUpgradeDeviceByPage(cityName, softVer, firmVer, onlineStatus, upgradeType, deviceModel, district);
        PageInfo<UpgradeDeviceListVO> pageInfo = new PageInfo<>();
        if (page == null) {
            return pageInfo;
        }
        pageInfo.setList(page.getResult());
        pageInfo.setTotal(page.getTotal());
        pageInfo.setPageNum(page.getPageNum());
        pageInfo.setPageSize(page.getPageSize());
        return pageInfo;
    }

    /**
     * 条件查询终端统计符合条件的终端数量
     *
     * @param cityCode      当前登录城市编码
     * @param onlineStatus  在线状态（在线OR离线）
     * @param softVer       软件版本
     * @param firmVer       固件版本
     * @param deviceModel   机型
     * @param machineNumber 机器码
     * @param propertyName  物业名称
     * @param deviceMac     设备mac
     * @param deviceIp      设备IP
     * @param administrator 管理人员
     * @param district      区/县
     * @param deviceStatus  设备状态:（0:可售  1:预拆除  2:维护）
     * @return Long
     */
    @Override
    public Long getDeviceCountByCondition(String cityCode, Integer onlineStatus, String softVer, String firmVer, String deviceModel,
                                          String machineNumber, String propertyName, String deviceMac,
                                          String deviceIp, String administrator, String district, Integer deviceStatus) {
        Long count = deviceMapper.getDeviceCountByCondition(cityCode, onlineStatus, softVer, firmVer, deviceModel, machineNumber, propertyName, deviceMac, deviceIp, administrator, district, deviceStatus);
        return count == null ? 0L : count;
    }

    /**
     * 查询所有终端中所有的mips版本号
     * hanqr 2018-08-14
     *
     * @return
     */
    @Override
    public List<String> listAllSoftwareVersion() {
        return deviceMapper.listAllSoftwareVersion();
    }

    @Override
    public void testNetworkSpeed(String deviceCodes, User user, String remortIP) throws ServiceException {
        DeviceSetting setting = new DeviceSetting();
        setting.setTestNetworkSpeedOnce(Boolean.TRUE);
        deviceSettingAndSaveLog(DeviceSettingType.TEST_NETWORK_SPEED, deviceCodes, user, remortIP, setting);
    }

}
